home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
ddj0492.zip
/
HANDPRIN.URC
/
Recognizer
/
Analyzer.c
next >
Wrap
Text File
|
1992-03-11
|
12KB
|
458 lines
/* All rights reserved. Copyright Ron Avitzur - 1992
*/
#include "Recognizer.h"
#define ANGLE_THRESHOLD 5
#define DOT_THRESHHOLD (Wacom?40:4)
#define PRE_ABS (Wacom?40:4)
#define PRE_RATIO_X 8
#define PRE_RATIO_Y 8
#define FIRST_RATIO_X 4
#define FIRST_RATIO_Y 4
#define MULTI_TIME_OUT TRAINING_TIME_OUT
short CollectStroke(where,theStroke)
Point where;
StrokePtr theStroke;
{
long down_time;
long Xmin,Xmax,Ymin,Ymax;
short still_down = TRUE,i = 0, result = 0;
Point last,drawme;
PenState thePnState;
GetPenState ( &thePnState );
if (Wacom) {
drawme.h = TAB_TO_SCREEN_X(where.h);
drawme.v = TAB_TO_SCREEN_Y(where.v);
GlobalToLocal(&drawme);
}
else
drawme = where;
PenMode(patXor);
PenSize(1,1);
MoveTo(drawme.h,drawme.v);
LineTo(drawme.h,drawme.v);
last = where;
Xmin = Xmax = where.h;
Ymin = Ymax = where.v;
theStroke->Ink[i++] = where;
down_time = TickCount();
while (still_down && i < MAX_POINTS) {
if (PauseIsMouse) {
if (!Training && TickCount() - down_time > MULTI_TIME_OUT &&
Xmax - Xmin < DOT_THRESHHOLD &&
Ymax - Ymin < DOT_THRESHHOLD)
{
short j;
for (j = 0; j < i; j++) {
where = theStroke->Ink[j];
if (Wacom) {
drawme.h = TAB_TO_SCREEN_X(where.h);
drawme.v = TAB_TO_SCREEN_Y(where.v);
GlobalToLocal(&drawme);
}
else
drawme = where;
MoveTo(drawme.h,drawme.v);
LineTo(drawme.h,drawme.v);
}
result = 1;
goto DONE;
}
}
if (Wacom) {
if (TRecord->updateFlags & FRESHDATA)
TRecord->updateFlags &= ~FRESHDATA;
else continue;
where.h = TRecord->xCoord;
where.v = TRecord->yCoord;
drawme.h = TAB_TO_SCREEN_X(TRecord->xCoord);
drawme.v = TAB_TO_SCREEN_Y(TRecord->yCoord);
GlobalToLocal(&drawme);
still_down = TRecord->buttons;
}
else {
GetMouse(&where);
drawme = where;
still_down = (StillDown() || StillDown()|| StillDown() || StillDown());
}
if (where.h == last.h && where.v == last.v) continue;
if (where.h > Xmax) Xmax = where.h;
if (where.h < Xmin) Xmin = where.h;
if (where.v > Ymax) Ymax = where.v;
if (where.v < Ymin) Ymin = where.v;
theStroke->Ink[i++] = last = where;
MoveTo(drawme.h,drawme.v); LineTo(drawme.h,drawme.v);
}
PenNormal();
theStroke->Ink_Num = i;
theStroke->end_time = TickCount();
theStroke->Height = Ymax - Ymin + 1;
theStroke->Width = Xmax - Xmin + 1;
theStroke->Xmin = Xmin;
theStroke->Xmax = Xmax;
theStroke->Ymin = Ymin;
theStroke->Ymax = Ymax;
theStroke->Aspect_Ratio = ((double)theStroke->Height - theStroke->Width) /
(theStroke->Height + theStroke->Width);
theStroke->Aspect_Ratio = (double)theStroke->Height / theStroke->Width;
Simplify(theStroke,theStroke->Ink,theStroke->Ink_Num);
Analyze(theStroke);
result = 0;
DONE:
SetPenState ( &thePnState );
return result;
}
short Process3(register Point *P,register Point *Q,short num,short,short,short,short);
short Process3(register Point *P,register Point *Q,short num,short xd,short yd,short xd2,short yd2)
{
register short i,n;
register short dx,dy;
n = 0;
P[0] = Q[0];
for (i = 1; i < num - 1; i++) {
dx = Q[i].h - P[n].h; dx = ABS(dx);
dy = Q[i].v - P[n].v; dy = ABS(dy);
if (dx + dy < PRE_ABS) continue;
if (dx < xd && dy < yd) continue;
if (n == 0 && dx < xd2 && dy < yd2) continue;
n++;
P[n] = Q[i];
}
dx = Q[num - 1].h - P[n].h;
dy = Q[num - 1].v - P[n].v;
if (ABS(dx) + ABS(dy) > PRE_ABS)
n++;
P[n] = Q[num - 1];
return n + 1;
}
short Dt(short t1,short t2);
short Dt(short t1,short t2)
{
short dt,a;
dt = t2 - t1;
a = ABS(dt);
if (a == 180) dt = 180;
else if (a > 180) {
if (t2>0) dt -= 360;
else if (t1>0) dt += 360;
}
return dt;
}
short Process4(Point *P,Point *Q,short N);
short Process4(Point *P,Point *Q,short N)
{
Point A,B,C;
short dt,t1,i,n = 1;
A = P[0] = Q[0];
B = P[1] = Q[1];
t1 = ATAN2(B.v - A.v,B.h - A.h);
for (i = 2; i < N; i++) {
C = Q[i];
dt = Dt(t1,ATAN2(C.v - B.v,C.h - B.h));
if (ABS(dt) < ANGLE_THRESHOLD)
P[n] = B = C;
else {
A = B;
B = C;
t1 = ATAN2(B.v - A.v,B.h - A.h);
n++;
P[n] = C;
}
}
return n + 1;
}
void Simplify(StrokePtr theStroke,Point *Ink,short N)
{
Point Q[MAX_POINTS];
short w = theStroke->Width, h = theStroke->Height;
short xd = w / PRE_RATIO_X,
yd = h / PRE_RATIO_Y,
xd2 = w / FIRST_RATIO_X,
yd2 = h / FIRST_RATIO_Y;
double ar = theStroke->Aspect_Ratio;
if (ar < 0.2) {
theStroke->P[0] = theStroke->Ink[0];
theStroke->P[1] = theStroke->Ink[theStroke->Ink_Num/2];
theStroke->P[2] = theStroke->Ink[theStroke->Ink_Num - 1];
N = 3;
}
else if (ar > 5.0)
N = Process3(theStroke->P,Ink,N,2*w,yd,2*w,yd2);
else N = Process3(theStroke->P,Ink,N,xd,yd,xd2,yd2);
theStroke->N = N;
}
#define DirectionA(t) ('0' + ((t + 10 + 45 + 180) / 90) % 4)
#define DirectionB(t) ('0' + ((t + 10 + 00 + 180) / 90) % 4)
#define Directiona(t) ('0' + ((t + 10 + 22 + 180) / 90) % 4)
#define Directionb(t) ('0' + ((t + 10 - 22 + 180) / 90) % 4)
#define DirectionC(t) ('0' + ((t + 10 + 22 + 180) / 45) % 8)
#define DirectionD(p) ('0' + (4*((p).h - theStroke->XminT) / theStroke->WidthT))
#define DirectionE(p) ('0' + (4*((p).v - theStroke->YminT) / theStroke->HeightT))
#define DirectionU(t) ('0' + ((t + 00 + 45 + 180) / 90) % 4)
#define FOO(name,fxn,type,array,end) \
void name(char *s,StrokePtr theStroke); \
void name(s,theStroke) \
register char *s; \
StrokePtr theStroke; \
{ \
register short i,d,n = 0; \
register type *T = theStroke->array; \
s[0] = fxn(*T++); \
i = theStroke->N - end; \
while (i-- > 0) { \
d = fxn(*T++); \
if (s[n] != d) \
s[++n] = d; \
} \
s[++n] = 0; \
}
FOO(Fxn1,DirectionA,short,T,2)
FOO(Fxn2,DirectionB,short,T,2)
FOO(Fxna,Directiona,short,T,2)
FOO(Fxnb,Directionb,short,T,2)
FOO(Fxn3,DirectionC,short,T,2)
FOO(FxnU,DirectionU,short,U,3)
FOO(Fxn4,DirectionD,Point,P,1)
FOO(Fxn5,DirectionE,Point,P,1)
#define Directionc(p) '0' + ((3*((p).h - theStroke->XminT) / theStroke->WidthT) + \
3*(3*((p).v - theStroke->YminT) / theStroke->HeightT))
void Fxnc(char *s,StrokePtr theStroke);
void Fxnc(register char *s,StrokePtr theStroke)
{
register short i= theStroke->N - 1,d,n = -1;
register Point p,*T = theStroke->P;
while (i-- > 0) {
p = *T++;
d = Directionc(p);
if (d == '4') continue;
if (d > '4') d -= 1;
if (n == -1 || s[n] != d)
s[++n] = d;
}
s[++n] = 0;
}
#define Directiond(p) '0' + ((2*((p).h - theStroke->XminT) / theStroke->WidthT) + \
2*(2*((p).v - theStroke->YminT) / theStroke->HeightT))
#define IN_MIDDLE(p) (Directionc(p) == '4')
void Fxnd(char *s,StrokePtr theStroke);
void Fxnd(register char *s,StrokePtr theStroke)
{
register short i= theStroke->N - 1,d,n = -1;
register Point p,*T = theStroke->P;
while (i-- > 0) {
p = *T++;
d = Directiond(p);
if (IN_MIDDLE(p)) continue;
if (n == -1 || s[n] != d)
s[++n] = d;
}
s[++n] = 0;
}
void ComputeT(theStroke)
StrokePtr theStroke;
{
register short *T = theStroke->T;
register short *U = theStroke->U;
register Point *P = theStroke->P;
register short i,N = theStroke->N;
for (i = 0; i < N - 1; i++)
T[i] = ATAN2(P[i+1].v-P[i].v,P[i+1].h-P[i].h);
T[N-1] = T[N-2];
for (i = 0; i < N - 2; i++)
U[i] = Dt(T[i],T[i+1]);
}
void Analyze(theStroke)
register StrokePtr theStroke;
{
char s[100];
register short *T = theStroke->T;
register Point *P = theStroke->P;
register short N = theStroke->N;
short Height = theStroke->Height,
Width = theStroke->Width,i;
if (Strokes)
{
StrokePtr lastStroke = Strokes->items[Strokes->num_items - 1];
Point lastPoint = lastStroke->P[lastStroke->N - 1];
theStroke->XmaxT = MAX(theStroke->Xmax,lastStroke->XmaxT);
theStroke->XminT = MIN(theStroke->Xmin,lastStroke->XminT);
theStroke->YmaxT = MAX(theStroke->Ymax,lastStroke->YmaxT);
theStroke->YminT = MIN(theStroke->Ymin,lastStroke->YminT);
theStroke->HeightT = (theStroke->YmaxT - theStroke->YminT + 1);
theStroke->WidthT = (theStroke->XmaxT - theStroke->XminT + 1);
}
else {
theStroke->XmaxT = theStroke->Xmax;
theStroke->XminT = theStroke->Xmin;
theStroke->YmaxT = theStroke->Ymax;
theStroke->YminT = theStroke->Ymin;
theStroke->HeightT = theStroke->Height;
theStroke->WidthT = theStroke->Width;
}
ComputeT(theStroke);
for (i=0;i<NUM_FEATURES;i++) {
(*HashFunctions[i])(s,theStroke);
ConvertStringToLong(s,&theStroke->S[i],Bits[i]);
}
theStroke->IsDot = ((Height < DOT_THRESHHOLD && Width < DOT_THRESHHOLD) || N == 1);
}
void ComputeBBox()
{
long Xmax,Xmin,Ymax,Ymin;
short i;
StrokePtr theStroke;
theStroke = Strokes->items[0];
Xmax = theStroke->Xmax; Xmin = theStroke->Xmin;
Ymax = theStroke->Ymax; Ymin = theStroke->Ymin;
for (i = 1; i < Strokes->num_items; i++) {
theStroke = Strokes->items[i];
if (theStroke->Xmax > Xmax) Xmax = theStroke->Xmax;
if (theStroke->Ymax > Ymax) Ymax = theStroke->Ymax;
if (theStroke->Xmin < Xmin) Xmin = theStroke->Xmin;
if (theStroke->Ymin < Ymin) Ymin = theStroke->Ymin;
}
if (Wacom) {
BBox.top = TAB_TO_SCREEN_Y(Ymin);
BBox.bottom = TAB_TO_SCREEN_Y(Ymax);
BBox.left = TAB_TO_SCREEN_X(Xmin);
BBox.right = TAB_TO_SCREEN_X(Xmax);
GlobalToLocal(&topLeft(BBox));
GlobalToLocal(&botRight(BBox));
}
else {
BBox.top = Ymin;
BBox.bottom = Ymax;
BBox.left = Xmin;
BBox.right = Xmax;
}
}
short StrokeMayContinue(void);
short StrokeMayContinue()
{
GesturePattern *gp;
short i,index;
StrokePtr lastStroke = Strokes->items[Strokes->num_items - 1];
List matches = lastStroke->matches;
if (matches == NIL) return FALSE;
if (matches->num_items == 0) return FALSE;
for (i = 0; i < matches->num_items; i++) {
index = (long)matches->items[i] & 0xFFFF;
gp = patterns->items[index];
if (gp->strokes->num_items > Strokes->num_items)
return TRUE;
}
return FALSE;
}
short TryCollectGesture(where,when)
Point where;
long when;
{
short i,j,code;
StrokePtr theStroke;
FreeStrokes();
theStroke = calloc(1,sizeof(StrokeData));
if (theStroke == NIL) {SysBeep(1); Debugger(); ExitToShell();}
theStroke->start_time = when;
if (CollectStroke(where,theStroke))
{
if (PauseIsMouse) {
free(theStroke);
return -1;
}
}
FlushEvents(everyEvent,0);
Append(&Strokes,(long)theStroke);
RecognizeStroke(0);
while (IN_PROXIMITY
&& TickCount() - theStroke->end_time < MULTI_TIME_OUT
&& StrokeMayContinue())
{
EventRecord event;
if (GetOSEvent(mDownMask,&event)) {
Point where;
if (Wacom) {
where.h = TRecord->xCoord;
where.v = TRecord->yCoord;
}
else {
where = event.where;
GlobalToLocal(&where);
}
theStroke = calloc(1,sizeof(StrokeData));
if (theStroke == NIL) {SysBeep(1); Debugger(); ExitToShell();}
theStroke->start_time = event.when;
CollectStroke(where,theStroke);
FlushEvents(everyEvent,0);
Append(&Strokes,(long)theStroke);
RecognizeStroke(Strokes->num_items - 1);
}
}
code = Recognize();
ComputeBBox();
if (Strokes)
for (i = 0; i < Strokes->num_items; i++) {
StrokePtr theStroke = Strokes->items[i];
PenState thePnState;
GetPenState(&thePnState);
PenMode(patXor);
for (j = 0; j < theStroke->Ink_Num; j++) {
Point drawme,p = theStroke->Ink[j];
if (Wacom) {
drawme.h = TAB_TO_SCREEN_X(p.h);
drawme.v = TAB_TO_SCREEN_Y(p.v);
GlobalToLocal(&drawme);
}
else
drawme = p;
MoveTo(drawme.h,drawme.v);
LineTo(drawme.h,drawme.v);
}
SetPenState(&thePnState);
}
FreeStrokes();
return code;
}
short VoteWeight[] = {3,3,3,3,3,3,3,3,3};
char Bits[] = {2,2,2,2,3,2,2,2,2};
VoidFunc HashFunctions[] = {Fxn1,Fxn2,Fxna,Fxnb,Fxnc,Fxnd,Fxn4,Fxn5,FxnU};
char *Names[NUM_FEATURES] = {"WNES","ABCD"};